/**
* Oxide
*
* Copyright (c) 2011 Dinosaur Kick Pty Ltd, All rights reserved.
*
* This source code is made available under the "Modified BSD" licensing arrangement.
* See license.txt for details.
*/
// ----------------------------------------------------------------------------
#include <cassert>
#include <boost/iterator/iterator_facade.hpp>
// ----------------------------------------------------------------------------
#ifndef O2_LEX_ITERATOR_INC
#define O2_LEX_ITERATOR_INC
namespace o2 {
namespace lex {
// ----------------------------------------------------------------------------

template <typename LexerT>
class iterator
	: public boost::iterator_facade<iterator<LexerT>, const typename LexerT::token_type, boost::single_pass_traversal_tag>
{
	public:
		typedef LexerT lexer_type;
		typedef typename lexer_type::char_type char_type;
		typedef typename lexer_type::token_type token_type;
		
		iterator(void)
			: m_lexer(0)
			, m_state(ITER_STATE_END)
			{ }

		explicit iterator(lexer_type& lxr)
			: m_lexer(&lxr)
			, m_state(ITER_STATE_BEGIN)
			{ }
		
		iterator(const iterator& iter)
			: m_lexer(iter.m_lexer)
			, m_state(iter.m_state)
			{ }

	private:
	    friend class boost::iterator_core_access;

		void increment(void)
		{
			prepare();
			advance();
		}

		bool equal(const iterator& iter) const
		{
			prepare();
			return (m_lexer == iter.m_lexer || iter.m_lexer == 0)
				&& m_state == iter.m_state;
		}

		const token_type& dereference(void) const
		{
			prepare();
			assert(m_lexer != 0);
			return m_lexer->current();
		}

		void advance(void)
		{
			if (m_state != ITER_STATE_END)
			{
				m_state = m_lexer->advance()
					? ITER_STATE_NORMAL
					: ITER_STATE_END;
			}
		}

		void prepare(void) const
		{
			if (m_state == ITER_STATE_BEGIN)
			{
				const_cast<iterator*>(this)->advance();
			}
		}

		lexer_type* m_lexer;
		enum
		{
			ITER_STATE_BEGIN,
			ITER_STATE_NORMAL,
			ITER_STATE_END
		} m_state;
};


// ----------------------------------------------------------------------------
} // namespace lex
} // namespace o2
#endif // O2_LEX_ITERATOR_INC
// ----------------------------------------------------------------------------
